package com.rc.saas.tenant.common.config;

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;

/**
 * 自定义 RestTemplate(使用HttpClient),实际开发中要避免每次http请求都实例化httpclient,restTemplate默认会复用连接,保证restTemplate单例即可
 */
@Configuration
public class HcRestTemplateConfig {
    //RestTemplate是Spring提供的用于访问Rest服务的客户端，
    //RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
    //调用RestTemplate的默认构造函数，RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求，
    //可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
    //ClientHttpRequestFactory接口主要提供了两种实现方式
    //  1、一种是SimpleClientHttpRequestFactory，使用J2SE提供的方式（既java.net包提供的方式）创建底层的Http请求连接。
    //  2、一种方式是使用HttpComponentsClientHttpRequestFactory方式，底层使用HttpClient访问远程的Http服务，使用HttpClient可以配置连接池和证书等信息。


    @Value("${hchttp.maxTotal}")
    private Integer maxTotal;

    @Value("${hchttp.defaultMaxPerRoute}")
    private Integer defaultMaxPerRoute;

    @Value("${hchttp.connectTimeout}")
    private Integer connectTimeout;

    @Value("${hchttp.connectionRequestTimeout}")
    private Integer connectionRequestTimeout;

    @Value("${hchttp.socketTimeout}")
    private Integer socketTimeout;

    @Value("${hchttp.staleConnectionCheckEnabled}")
    private boolean staleConnectionCheckEnabled;

    @Value("${hchttp.validateAfterInactivity}")
    private Integer validateAfterInactivity;

    @Bean("hcRestTemplate")
    public RestTemplate hcRestTemplate(ClientHttpRequestFactory hcClientHttpRequestFactory) {
        //return new RestTemplate(hcClientHttpRequestFactory);

        RestTemplate restTemplate = new RestTemplate(hcClientHttpRequestFactory);

        //RestTemplate设置编码,spring转换默认编码是ISO_8859_1,如果乱码可修改支持中文编码
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));

        //消息转换器列表
        //List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
        //for (HttpMessageConverter c : messageConverters) {
        //    if (c instanceof StringHttpMessageConverter) {
        //        ((StringHttpMessageConverter) c).setDefaultCharset(Charset.forName("utf-8"));
        //    }
        //}

        return restTemplate;
    }

    @Bean("hcClientHttpRequestFactory")
    public ClientHttpRequestFactory hcClientHttpRequestFactory() {
        return new HttpComponentsClientHttpRequestFactory(httpClient());
    }

    /**
     * 使用使用HttpClient创建RestTemplate
     * @return
     */
    @Bean
    public HttpClient httpClient() {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();

        //1.创建连接池管理器
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
        connectionManager.setMaxTotal(maxTotal); // 最大连接数
        connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);    //单个路由最大连接数
        connectionManager.setValidateAfterInactivity(validateAfterInactivity); // 最大空间时间
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(socketTimeout)        //服务器返回数据(response)的时间，超过抛出read timeout
                .setConnectTimeout(connectTimeout)      //连接上服务器(握手成功)的时间，超出抛出connect timeout
                .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled) // 提交前检测是否可用
                .setConnectionRequestTimeout(connectionRequestTimeout)//从连接池中获取连接的超时时间，超时间未拿到可用连接，会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                .build();

        //2.创建httpclient对象
        return HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                //httpClient默认重试策略DefaultHttpRequestRetryHandler针对连接超时和获取数据超时并不会重试，重试次数为3
                //.setRetryHandler(new DefaultHttpRequestRetryHandler())
                .build();
    }
}
